import path from 'path';
const fs = require('fs');
import { app, BrowserWindow, shell, ipcMain } from 'electron';
import { RowDataPacket } from 'mysql2/promise';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
import {
  makeUrlsLoop,
  insertDataToMysql,
  getHousePrice,
  collectLianJiaData,
  testDatabaseConnection,
  createStockDataTable,
  readDataFiles,
  testInsertData,
  formalInsertData,
  getDuplicateData,
  queryDatabase,
} from '../utils/utils';
import { throttle } from 'lodash';
import os from 'os';

setInterval(() => {
  const memoryUsage = process.memoryUsage();
  const cpuUsage = os.cpus();

  // log.info(`Memory Usage: ${memoryUsage.heapUsed / 1024 / 1024} MB`);
  // log.info(`CPU Usage: ${JSON.stringify(cpuUsage)}`);
}, 30000); // 每30秒记录一次
// 配置日志
log.transports.file.level = 'info';
log.transports.file.maxSize = 5 * 1024 * 1024; // 限制日志文件大小为5MB
log.transports.file.file = __dirname + '/log.txt'; // 指定日志文件路径
// 创建一个节流函数来限制日志记录频率
const throttledLog = throttle(
  (message: string) => {
    log.info(message);
  },
  30000,
  { trailing: false },
);

// 使用日志
log.info('This is an info message');
log.warn('This is a warning message');
log.error('This is an error message');

// 使用节流日志
throttledLog('This is a throttled info message');
class AppUpdater {
  constructor() {
    log.transports.file.level = 'info';
    autoUpdater.logger = log;
    autoUpdater.checkForUpdatesAndNotify();
  }
}

let mainWindow: BrowserWindow | null = null;

ipcMain.on('ipc-example', async (event, arg) => {
  const msgTemplate = (pingPong: string) => `IPC test: ${pingPong}`;
  event.reply('ipc-example', msgTemplate('pong'));
});

ipcMain.on('start-fetching-data', async (event, arg) => {
  // 假设 arg 包含了 URL 列表
  let stockArray = await makeUrlsLoop();
  let res: any = await insertDataToMysql(event, arg);
  event.reply('data-fetching-complete', '已完成', stockArray);
});

ipcMain.on('start-insertDataToMysql', async (event, arg) => {
  let res: any = await insertDataToMysql(event, arg);
  event.reply('start-insertDataToMysql', '数据插入完成', res);
});

ipcMain.on('connect-database', async (event, arg) => {
  try {
    const res = await testDatabaseConnection();
    event.reply('database-connect-result', '数据库连接成功', res);
  } catch (error) {
    event.reply('database-connect-result', '数据库连接失败', error);
  }
});

ipcMain.on('create-table', async (event, arg) => {
  try {
    const res = await createStockDataTable();
    event.reply('create-table-result', '创建表成功', res);
  } catch (error) {
    event.reply('create-table-result', '创建表失败', error);
  }
});

ipcMain.on('read-data-files', async (event, arg) => {
  try {
    const res = await readDataFiles();
    event.reply('read-data-result', '读取数据成功', res);
  } catch (error) {
    event.reply('read-data-result', '读取数据失败', error);
  }
});

ipcMain.on('test-insert-data', async (event, arg) => {
  try {
    const res = await testInsertData(event);
    event.reply('test-insert-result', '实验性插入成功', res);
  } catch (error) {
    event.reply('test-insert-result', '实验性插入失败', error);
  }
});

ipcMain.on('formal-insert-data', async (event, arg) => {
  try {
    const res = await formalInsertData(event);
    event.reply('formal-insert-result', res);
  } catch (error: any) {
    event.reply('formal-insert-result', { success: false, message: error.message });
  }
});

ipcMain.on('get-duplicate-data', async (event, arg) => {
  try {
    const res = await getDuplicateData();
    event.reply('duplicate-data-result', res);
  } catch (error: any) {
    event.reply('duplicate-data-result', { success: false, message: error.message });
  }
});

ipcMain.on('start-fetching-houseprice-data', async (event, arg) => {
  // 收集数据
  collectLianJiaData();
  let res: any = await getHousePrice({});
  console.log(res);
  event.reply('houseprice-data-fetching-complete', '数据插入完成', res || []);
});

ipcMain.on('start-move-file', async (event, arg) => {
  try {
    console.log('开始文件迁移');

    // 1. 设置源目录和目标目录
    // 源目录：项目根目录下的txtdata文件夹（相对路径）
    const sourceDirectory = path.join(__dirname, '../../txtdata');

    // 目标目录：D盘的"数据"文件夹（绝对路径）
    const destinationDirectory = 'D:/数据';

    // 2. 准备目标文件夹路径（按日期分类）
    // 获取当前日期（格式：YYYYMMDD）
    const currentDate = new Date().toISOString().slice(0, 10).replace(/-/g, '');

    // 构建完整的目标文件夹路径（D:/数据/20250611）
    const targetFolderPath = path.join(destinationDirectory, currentDate);

    // 3. 创建目标文件夹（如果不存在）
    if (!fs.existsSync(targetFolderPath)) {
      fs.mkdirSync(targetFolderPath, { recursive: true });
      console.log(`已创建目标文件夹: ${targetFolderPath}`);
    } else {
      console.log(`目标文件夹已存在: ${targetFolderPath}`);
    }

    // 4. 获取源目录中的所有文件
    const files = fs.readdirSync(sourceDirectory);
    console.log(`找到 ${files.length} 个文件待迁移`);

    // 5. 使用Promise.all处理所有文件迁移
    await Promise.all(
      files.map((file) => {
        return new Promise<void>(async (resolve, reject) => {
          try {
            // 构建完整的源文件路径和目标文件路径
            const sourceFilePath = path.join(sourceDirectory, file);
            const destinationFilePath = path.join(targetFolderPath, file);

            // 6. 检查文件是否可访问
            await fs.promises.access(
              sourceFilePath,
              fs.constants.R_OK | fs.constants.W_OK,
            );

            // 7. 创建读写流进行文件复制（支持跨磁盘）
            const readStream = fs.createReadStream(sourceFilePath);
            const writeStream = fs.createWriteStream(destinationFilePath);

            // 8. 处理错误事件
            readStream.on('error', (err) => {
              console.error(`读取文件错误: ${sourceFilePath}`, err);
              reject(err);
            });

            writeStream.on('error', (err) => {
              console.error(`写入文件错误: ${destinationFilePath}`, err);
              reject(err);
            });

            // 9. 复制完成后删除原文件
            writeStream.on('finish', async () => {
              try {
                // 延迟删除以避免文件锁定问题
                await new Promise((resolve) => setTimeout(resolve, 100));

                // 尝试删除文件
                await fs.promises.unlink(sourceFilePath);
                console.log(`成功迁移: ${file} → ${targetFolderPath}`);
                resolve();
              } catch (deleteErr: any) {
                console.error(`删除原文件失败: ${sourceFilePath}`, deleteErr);

                // 如果是权限问题，尝试使用管理员权限删除
                if (deleteErr.code === 'EPERM') {
                  console.warn('检测到权限问题，尝试使用管理员权限运行应用');
                }
                reject(deleteErr);
              }
            });

            // 10. 开始文件复制
            readStream.pipe(writeStream);
          } catch (accessErr: any) {
            // 11. 文件访问错误处理
            console.error(`文件访问错误: ${file}`, accessErr);

            // 特殊处理权限错误
            if (accessErr.code === 'EPERM') {
              console.warn(`文件 ${file} 可能被其他程序锁定`);
            }

            // 即使一个文件失败，也继续处理其他文件
            resolve();
          }
        });
      }),
    );

    // 12. 所有文件迁移完成，发送成功消息
    console.log(`文件迁移完成到: ${targetFolderPath}`);
    event.reply('file-move-complete', '文件迁移完成', 'success');
  } catch (error: any) {
    // 13. 全局错误处理
    console.error('文件迁移过程中出错:', error);

    // 提取错误信息
    const errorMessage = error instanceof Error ? error.message : String(error);

    // 发送错误消息到渲染进程
    event.reply('file-move-complete', `文件迁移出错: ${errorMessage}`, 'error');
  }
});


// 其他现有导入...

// 修复后的检查最新数据事件
ipcMain.on('check-latest-data', async (event) => {
  try {
    console.info('开始检查最新数据日期...');
    console.info('执行SQL查询: SELECT code, MAX(date) as latest_date FROM stock_data GROUP BY code');
    // 1. 查询每个股票的最新日期（已通过工具方法保证类型）
    const stockLatestDates = await queryDatabase(`
      SELECT code, MAX(date) as latest_date
      FROM stock_data
      GROUP BY code
    `);
    console.info(`查询返回原始结果: ${JSON.stringify(stockLatestDates, null, 2)}`);
    // 检查查询结果有效性
    if (!Array.isArray(stockLatestDates) || stockLatestDates.length === 0) {
      throw new Error('未查询到任何股票数据');
    }

    console.info(`查询到 ${stockLatestDates.length} 个股票的最新日期`);

    // 2. 统计日期频率
    const dateFrequency: Record<string, number> = {};
    stockLatestDates.forEach((item: RowDataPacket) => {
      const date = item.latest_date as string;
      if (date) {
        dateFrequency[date] = (dateFrequency[date] || 0) + 1;
      }
    });

    // 处理无日期数据的情况
    if (Object.keys(dateFrequency).length === 0) {
      throw new Error('未找到有效的日期数据');
    }

    // 3. 找到最常见的最新日期
    const mostRecentDate = Object.entries(dateFrequency)
      .sort((a, b) => b[1] - a[1])[0][0];
    const mostRecentDateCount = dateFrequency[mostRecentDate];
    console.log(`最新的日期应该是 the newest data is ${mostRecentDate}，by return data 根据数据库最新的日期返出来打印`);
    // 4. 筛选缺失数据的股票
    const missingCodes = stockLatestDates
      .filter((item: RowDataPacket) => {
        return item.latest_date !== mostRecentDate;
      })
      .map((item: RowDataPacket) => {
        return item.code as string;
      });

    console.log(`display  ${missingCodes.length}  codes have no latest Data`);

    // 5. 返回结果给渲染进程
    event.reply('latest-data-result', {
      success: true,
      totalStocks: stockLatestDates.length,
      mostRecentDate,
      mostRecentDateCount,
      missingCount: missingCodes.length,
      missingCodes
    });

  } catch (error: any) {
    log.error('检查最新数据失败:', error);
    event.reply('latest-data-result', {
      success: false,
      message: error.message || '检查最新数据时发生未知错误'
    });
  }
});


if (process.env.NODE_ENV === 'production') {
  const sourceMapSupport = require('source-map-support');
  sourceMapSupport.install();
}

const isDebug =
  process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';

if (isDebug) {
  require('electron-debug')();
}

const installExtensions = async () => {
  try {
    const installer = require('electron-devtools-installer');
    const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
    const extensions = ['REACT_DEVELOPER_TOOLS'];

    return installer
      .default(
        extensions.map((name) => installer[name]),
        forceDownload,
      )
      .catch((err: unknown) => {
        console.log('Extension installation failed:', err);
        // 即使扩展安装失败，也返回 resolved promise
        return Promise.resolve();
      });
  } catch (err: unknown) {
    console.log('Failed to install extensions:', err);
    // 确保返回 resolved promise
    return Promise.resolve();
  }
};

const createWindow = async () => {
  if (isDebug) {
    try {
      await installExtensions();
    } catch (err: unknown) {
      console.log('Extension installation failed, but continuing app startup:', err);
    }
  }

  const RESOURCES_PATH = app.isPackaged
    ? path.join(process.resourcesPath, 'assets')
    : path.join(__dirname, '../../assets');

  const getAssetPath = (...paths: string[]): string => {
    return path.join(RESOURCES_PATH, ...paths);
  };

  mainWindow = new BrowserWindow({
    show: false,
    width: 1024,
    height: 728,
    icon: getAssetPath('icon.png'),
    webPreferences: {
      preload: app.isPackaged
        ? path.join(__dirname, 'preload.js')
        : path.join(__dirname, '../../.erb/dll/preload.js'),
    },
  });

  mainWindow.loadURL(resolveHtmlPath('index.html'));

  mainWindow.on('ready-to-show', () => {
    if (!mainWindow) {
      throw new Error('"mainWindow" is not defined');
    }
    if (process.env.START_MINIMIZED) {
      mainWindow.minimize();
    } else {
      mainWindow.show();
    }
  });

  mainWindow.on('closed', () => {
    mainWindow = null;
  });

  const menuBuilder = new MenuBuilder(mainWindow);
  menuBuilder.buildMenu();

  // Open urls in the user's browser
  mainWindow.webContents.setWindowOpenHandler((edata) => {
    shell.openExternal(edata.url);
    return { action: 'deny' };
  });

  // Remove this if your app does not use auto updates
  // eslint-disable-next-line
  new AppUpdater();
};

/**
 * Add event listeners...
 */

app.on('window-all-closed', () => {
  // Respect the OSX convention of having the application in memory even
  // after all windows have been closed
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app
  .whenReady()
  .then(() => {
    createWindow();
    app.on('activate', () => {
      // On macOS it's common to re-create a window in the app when the
      // dock icon is clicked and there are no other windows open.
      if (mainWindow === null) createWindow();
    });
  })
  .catch(console.log);
